package com.net.protocol.util;

import java.util.Calendar;
import java.util.Date;
import java.util.Locale;

/**
 * 位操作工具类
 *
 */
public class BitUtils {

    /**
     * 将字节写入缓冲
     *
     * @param buffer 输入缓冲
     * @param offset 偏移量
     * @param bytes  要写入的值
     */
    public static void setBytes(byte[] buffer, int offset, byte[] bytes) {
        for (byte b : bytes) {
            buffer[offset++] = b;
        }
    }

    /**
     * 将16位整数(int)写入缓冲中(小端端模式，即低位在前)
     *
     * @param buffer 输入缓冲
     * @param offset 偏移量
     * @param value  要写入的值
     */
    public static void setInt16(byte[] buffer, int offset, int value) {
        buffer[offset++] = (byte) value;
        buffer[offset] = (byte) (value >> 8);
    }

    /**
     * 将32位整数(int)写入缓冲中(大端模式，即高位在前)
     *
     * @param buffer 输入缓冲
     * @param offset 偏移量
     * @param value  要写入的值
     */
    public static void setInt32(byte[] buffer, int offset, int value) {
        setInt16(buffer, offset, (value >> 16));
        setInt16(buffer, offset + 2, value);
    }

    /**
     * 将64位整数(long)写入缓冲中(大端模式，即高位在前)
     *
     * @param buffer 输入缓冲
     * @param offset 偏移量
     * @param value  要写入的值
     */
    public static void setLong(byte[] buffer, int offset, long value) {
        setInt32(buffer, offset, (int) (value >> 32));
        setInt32(buffer, offset + 4, (int) value);
    }

    /**
     * 将BCD数据写入缓冲
     *
     * @param buffer 输入缓冲
     * @param offset 偏移量
     * @param value  要写入的数据
     * @param length BCD数据所占字节数
     */
    public static void setBCD(byte[] buffer, int offset, String value, int length) {
        value = zeroFill(value, length * 2); //数据不满指定长度则前端补零
        for (int i = 0; i < length; i++) {
            int high = Character.getNumericValue(value.charAt(i * 2));
            int low = Character.getNumericValue(value.charAt(i * 2 + 1));
            buffer[offset++] = (byte) (((high << 4) & 0xF0) | (low & 0x0F));
        }
    }

    /**
     * 将时间写入缓冲
     *
     * @param buffer 输入缓冲
     * @param offset 偏移量
     * @param time   时间
     */
    public static void setTime(byte[] buffer, int offset, Date time) {
        Calendar cal = Calendar.getInstance(Locale.getDefault());
        cal.setTime(time);
        buffer[offset++] = (byte) (cal.get(Calendar.YEAR) % 100); //年(YY)
        buffer[offset++] = (byte) (cal.get(Calendar.MONTH) + 1); //月(MM)
        buffer[offset++] = (byte) (cal.get(Calendar.DAY_OF_MONTH)); //日(DD)
        buffer[offset++] = (byte) (cal.get(Calendar.HOUR_OF_DAY)); //时(YY)
        buffer[offset++] = (byte) (cal.get(Calendar.MINUTE)); //分(mm)
        buffer[offset] = (byte) (cal.get(Calendar.SECOND)); //秒(ss)
    }

    /**
     * 读取16位整数(小端模式，即低位在前)
     *
     * @param buffer 数据源
     * @param offset 读取的偏移位置，随着读取进度会更新此偏移
     */
    public static int readInt16(byte[] buffer, int offset) {
        return (parseByteToUnsignedInt(buffer[offset++]))
                | parseByteToUnsignedInt(buffer[offset++]) << 8;
    }

    /**
     * 读取32位整数(大端模式，即高位在前)
     *
     * @param buffer 数据源
     * @param offset 读取的偏移位置，随着读取进度会更新此偏移
     */
    public static int readInt32(byte[] buffer, int offset) {
        return (readInt16(buffer, offset) << 16) | readInt16(buffer, offset + 2);
    }

    /**
     * 读取64位整数(大端模式，即高位在前)
     *
     * @param buffer 数据源
     * @param offset 读取的偏移位置，随着读取进度会更新此偏移
     */
    public static long readLong(byte[] buffer, int offset) {
        return readInt32(buffer, offset) | readInt32(buffer, offset + 4);
    }

    /**
     * 读取BCD数据
     *
     * @param buffer 数据源
     * @param offset 读取的偏移位置，随着读取进度会更新此偏移
     * @param length BCD数据长度
     */
    public static String readBCD(byte[] buffer, int offset, int length) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            byte b = buffer[offset++];
            sb.append((b >> 4) & 0x0F);
            sb.append(b & 0x0F);
        }
        return sb.toString();
    }

    /**
     * 读取时间
     *
     * @param buffer 数据源
     * @param offset 读取的偏移位置，随着读取进度会更新此偏移
     */
    public static Date readTime(byte[] buffer, int offset) {
        Calendar cal = Calendar.getInstance(Locale.getDefault());
        cal.set(Calendar.YEAR, 2000 + buffer[offset++]); //年(YY)
        cal.set(Calendar.MONTH, buffer[offset++] - 1); //月份
        cal.set(Calendar.DAY_OF_MONTH, buffer[offset++]); //日(DD)
        cal.set(Calendar.HOUR_OF_DAY, buffer[offset++]); //时(YY)
        cal.set(Calendar.MINUTE, buffer[offset++]); //分(mm)
        cal.set(Calendar.SECOND, buffer[offset]); //秒(ss)
        return cal.getTime();
    }

    /**
     * 将byte转化为无符号int
     */
    private static int parseByteToUnsignedInt(byte b) {
        return b < 0 ? (b + 256) : b;
    }

    /**
     * 字串不满指定长度，则在前面补零
     *
     * @param value  字串
     * @param length 指定长度
     */
    public static String zeroFill(String value, int length) {
        if (value.length() < length) {
            StringBuilder sb = new StringBuilder(value);
            for (int i = 0; i < length - value.length(); i++) {
                sb.insert(0, 0);
            }
            return sb.toString();
        }
        return value;
    }

    public static void main(String[] args) {
        long i = 1000L;
        byte[] bytes = new byte[8];
        BitUtils.setLong(bytes, 0, i);
        System.out.println(Hex.encodeHexStr(bytes));
        long j = BitUtils.readLong(bytes, 0);
        System.out.println(Long.toHexString(j));
        System.out.println(i >> 32);
    }
}
